#include "stdafx.h"

// *****************************************************************************************
//
// NAPYR2 (http://p-nand-q.com/python/napyr.html)
//
// Copyright (c) 2014, Gerson Kurz
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// 
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 
// 2. Redistributions in binary form must reproduce the above copyright notice, this
//    list of conditions and the following disclaimer in the documentation and/or other
//    materials provided with the distribution.
// 
// 3. Neither the name of the copyright holder nor the names of its contributors may
//    be used to endorse or promote products derived from this software without
//    specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// *****************************************************************************************

#include "python.h"
#include "napyr2_Call.h"
#include "napyr2_Runtime.h"
#include "napyr2_Helpers.h"


namespace napyr2 { // begins here

PythonCall::PythonCall( napyr2::PythonRuntime* pPythonRuntime, LPCSTR lpszName )
    :   m_pyFunc( NULL ), 
        m_pyArgs( NULL ), 
        m_pPythonRuntime( pPythonRuntime ), 
        m_lpszName( lpszName )        
{
    if( pPythonRuntime->IsInitialized() )
    {
        m_GIL = PyGILState_Ensure();

		PyObject* pyMain = pPythonRuntime->GetMainObject();
        if( pyMain != NULL )
        {
            m_pyFunc = PyDict_GetItemString(PyModule_GetDict(pyMain), lpszName);
            
            if(m_pyFunc && !PyCallable_Check(m_pyFunc))
            {
                m_pyFunc = NULL;
            }
        }
        else
        {
        }
    }
}

PythonCall::~PythonCall()
{   
	if( m_pPythonRuntime->IsInitialized() )
    {
        if( m_pyArgs )
        {
            Py_DECREF(m_pyArgs);
            m_pyArgs = NULL;
        }
        PyGILState_Release(m_GIL);
    }
    //else PAssert( FALSE );
}

void PythonCall::Add( const PythonObject& value )
{
	m_args.push_back(value.AddRef());
}
    
bool PythonCall::BuildArgs()
{
	if( m_pyArgs != NULL )
		return false;

	int n = m_args.size();
	m_pyArgs = PyTuple_New(n);
	if( m_pyArgs == NULL )
		return false;

	for(int i = 0; i < n; i++)
	{
		PyTuple_SET_ITEM(m_pyArgs, i, m_args[i]);
		m_args[i] = NULL;
	}
	return true;
}

bool PythonCall::Call(PythonObject& result)
{
    if( m_pyFunc && BuildArgs()  )
    {
        PyObject* pyResult = PyObject_CallObject(m_pyFunc, m_pyArgs);
        if ( pyResult != NULL )
        {
			result.CreateFromResult(pyResult); // destructor of 'result' will call Py_DECREF for us
			return true;
        }
    }
    return 0;
}

bool PythonCall::Call()
{
    if( m_pyFunc && BuildArgs() )
    {
        PyObject* pyValue = PyObject_CallObject(m_pyFunc, m_pyArgs);
        if ( pyValue != NULL )
        {
            Py_DECREF(pyValue);
			return true;
        }
    }
	return false;
}

} // namespace napyr2 ends here.


